using System;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RCPostRenderFeature : ScriptableRendererFeature
{
    public Shader m_Shader;
    Material m_Material;

    public Shader m_RCShader;
    public Texture2D m_NoiseTexture;
    Material m_RCMaterial;

    public Shader m_JFShader;
    Material m_JFMaterial;

    enum Pipeline {
        Simple,
        RadianceCascades,
        RadianceCascadesOpt
    }

    const int CascadeLevelNum = 6;
    class RCPostRenderPass : ScriptableRenderPass
    {
        // Define All Params
        public float    Cascade0_RayMarchingLength              = 0.002f;
        public float    CascadeN_RayMarchingLengthRate          = 4.5f;
        public float2   Cascade0_ProbeSizePix                   = new float2(1f, 1f);
        public int2     Cascade0_AngleSize                      = new int2(1, 4);
        public int2     CascadeN_AngleSizeRate                  = new int2(2, 2);

        ProfilingSampler m_RayMarchingProfilingSampler  = new ProfilingSampler("RCPost_RayMarching");
        ProfilingSampler m_MergeProfilingSampler        = new ProfilingSampler("RCPost_Merge");
        ProfilingSampler m_RenderProfilingSampler       = new ProfilingSampler("RCPost_Render");
        ProfilingSampler m_CombineProfilingSampler      = new ProfilingSampler("RCPost_Combine");
        ProfilingSampler m_JumpFloodInitProfilingSampler = new ProfilingSampler("JF_Init");
        ProfilingSampler m_JumpFloodLoopProfilingSampler = new ProfilingSampler("JF_Loop");
        public Material m_Material;
        public Material m_RCMaterial;
        public Material m_JFMaterial;
        public Texture2D m_NoiseTexture;

        public RTHandle m_CameraColorTarget;
        public RTHandle m_CameraDepthTarget;
        RTHandle[] TempRTHandle_RayMarching     = new RTHandle[CascadeLevelNum];
        RTHandle[] TempRTHandle_Merge           = new RTHandle[2];

        RTHandle[] TempRTHandle_Sdf = new RTHandle[3];

        // Runtime Params
        Vector4[] Cascade_ProbeNum_TexSize      = new Vector4[CascadeLevelNum];
        Vector4[] Cascade_ProbeSize_AngleSize   = new Vector4[CascadeLevelNum];

        Pipeline UsedPipeline = Pipeline.RadianceCascadesOpt;

        float TotalTime = 0.0f;
        
        private void SimpleRenderSetup(CommandBuffer CmdBuf, ref RenderingData renderingData) {}

        private Vector2 PreCalculateTexSize(int BaseWidth, int BaseHeight) {
            float BaseProbeWidth  = (float)Math.Ceiling(BaseWidth  / Cascade0_ProbeSizePix.x);
            float BaseProbeHeight = (float)Math.Ceiling(BaseHeight / Cascade0_ProbeSizePix.y);

            for (int CascadeLevel = 1; CascadeLevel < CascadeLevelNum; CascadeLevel++) {
                BaseProbeWidth  = (float)Math.Ceiling(BaseProbeWidth  / 2);
                BaseProbeHeight = (float)Math.Ceiling(BaseProbeHeight / 2);
            }

            return new Vector2(
                BaseProbeWidth  * Cascade0_AngleSize.x * (float)Math.Pow(CascadeN_AngleSizeRate.x, CascadeLevelNum - 1), 
                BaseProbeHeight * Cascade0_AngleSize.y * (float)Math.Pow(CascadeN_AngleSizeRate.y, CascadeLevelNum - 1)
            );
        }
        private void RadianceCascadesRenderSetup(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            // Step0. Get Render Data
            RenderTextureDescriptor RTDescriptor = renderingData.cameraData.cameraTargetDescriptor;
            RTDescriptor.depthBufferBits = 0;
            RTDescriptor.colorFormat = RenderTextureFormat.ARGBHalf;
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Sdf[0], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Sdf[1], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Sdf[2], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);

            // Step1. PreCalculate Final Texture Size, Related to ProbeNum&AngleSize
            Vector2 TexSize = PreCalculateTexSize(RTDescriptor.width, RTDescriptor.height);
            RTDescriptor.width  = (int)(TexSize.x);
            RTDescriptor.height = (int)(TexSize.y);

            // Step2. Setup 0 State
            Cascade_ProbeSize_AngleSize[0].x = Cascade0_ProbeSizePix.x;
            Cascade_ProbeSize_AngleSize[0].y = Cascade0_ProbeSizePix.y;
            Cascade_ProbeSize_AngleSize[0].z = Cascade0_AngleSize.x;
            Cascade_ProbeSize_AngleSize[0].w = Cascade0_AngleSize.y;
            Cascade_ProbeNum_TexSize[0].x = (float)Math.Ceiling(TexSize.x / Cascade0_ProbeSizePix.x);
            Cascade_ProbeNum_TexSize[0].y = (float)Math.Ceiling(TexSize.y / Cascade0_ProbeSizePix.y);
            Cascade_ProbeNum_TexSize[0].z = TexSize.x;
            Cascade_ProbeNum_TexSize[0].w = TexSize.y;

            // Step3. Calc N State
            for (int CascadeLevel = 1; CascadeLevel < CascadeLevelNum; CascadeLevel++) {
                Cascade_ProbeSize_AngleSize[CascadeLevel].x = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].x * 2;
                Cascade_ProbeSize_AngleSize[CascadeLevel].y = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].y * 2;
                Cascade_ProbeSize_AngleSize[CascadeLevel].z = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].z * CascadeN_AngleSizeRate.x;
                Cascade_ProbeSize_AngleSize[CascadeLevel].w = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].w * CascadeN_AngleSizeRate.y;
                Cascade_ProbeNum_TexSize[CascadeLevel].x = TexSize.x / Cascade_ProbeSize_AngleSize[CascadeLevel].z;
                Cascade_ProbeNum_TexSize[CascadeLevel].y = TexSize.y / Cascade_ProbeSize_AngleSize[CascadeLevel].w;
                Cascade_ProbeNum_TexSize[CascadeLevel].z = TexSize.x;
                Cascade_ProbeNum_TexSize[CascadeLevel].w = TexSize.y;
            }

            // Step3. Allocate Memory
            for (int CascadeLevel = 0; CascadeLevel < CascadeLevelNum; CascadeLevel++) {
                RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_RayMarching[CascadeLevel], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            }
            
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Merge[0], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Merge[1], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
        }
        private void RadianceCascadesOptRenderSetup(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            // Step0. Get Render Data
            RenderTextureDescriptor RTDescriptor = renderingData.cameraData.cameraTargetDescriptor;
            RTDescriptor.depthBufferBits = 0;
            RTDescriptor.colorFormat = RenderTextureFormat.ARGBHalf;
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Sdf[0], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Sdf[1], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Sdf[2], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);

            // Step1. PreCalculate Final Texture Size, Related to ProbeNum&AngleSize
            Vector2 TexSize = PreCalculateTexSize(RTDescriptor.width, RTDescriptor.height);
            RTDescriptor.width  = (int)(TexSize.x);
            RTDescriptor.height = (int)(TexSize.y);

            // Step2. Setup 0 State
            Cascade_ProbeSize_AngleSize[0].x = Cascade0_ProbeSizePix.x;
            Cascade_ProbeSize_AngleSize[0].y = Cascade0_ProbeSizePix.y;
            Cascade_ProbeSize_AngleSize[0].z = Cascade0_AngleSize.x;
            Cascade_ProbeSize_AngleSize[0].w = Cascade0_AngleSize.y;
            Cascade_ProbeNum_TexSize[0].x = (float)Math.Ceiling(TexSize.x / Cascade0_ProbeSizePix.x);
            Cascade_ProbeNum_TexSize[0].y = (float)Math.Ceiling(TexSize.y / Cascade0_ProbeSizePix.y);
            Cascade_ProbeNum_TexSize[0].z = TexSize.x;
            Cascade_ProbeNum_TexSize[0].w = TexSize.y;

            // Step3. Calc N State
            for (int CascadeLevel = 1; CascadeLevel < CascadeLevelNum; CascadeLevel++) {
                Cascade_ProbeSize_AngleSize[CascadeLevel].x = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].x * 2;
                Cascade_ProbeSize_AngleSize[CascadeLevel].y = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].y * 2;
                Cascade_ProbeSize_AngleSize[CascadeLevel].z = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].z * CascadeN_AngleSizeRate.x;
                Cascade_ProbeSize_AngleSize[CascadeLevel].w = Cascade_ProbeSize_AngleSize[CascadeLevel - 1].w * CascadeN_AngleSizeRate.y;
                Cascade_ProbeNum_TexSize[CascadeLevel].x = TexSize.x / Cascade_ProbeSize_AngleSize[CascadeLevel].z;
                Cascade_ProbeNum_TexSize[CascadeLevel].y = TexSize.y / Cascade_ProbeSize_AngleSize[CascadeLevel].w;
                Cascade_ProbeNum_TexSize[CascadeLevel].z = TexSize.x;
                Cascade_ProbeNum_TexSize[CascadeLevel].w = TexSize.y;
            }

            // Step3. Allocate Memory            
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Merge[0], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
            RenderingUtils.ReAllocateIfNeeded(ref TempRTHandle_Merge[1], RTDescriptor, FilterMode.Point, TextureWrapMode.Clamp);
        }

        // This method is called before executing the render pass.
        // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
        // When empty this render pass will render to the active camera render target.
        // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
        // The render pipeline will ensure target setup and clearing happens in a performant manner.
        public override void OnCameraSetup(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            TotalTime += Time.deltaTime;
            switch (UsedPipeline) {
                case Pipeline.Simple: { SimpleRenderSetup(CmdBuf, ref renderingData); break; }
                case Pipeline.RadianceCascades: { RadianceCascadesRenderSetup(CmdBuf, ref renderingData); break; }
                case Pipeline.RadianceCascadesOpt: { RadianceCascadesOptRenderSetup(CmdBuf, ref renderingData); break; }
            }
        }

        // Here you can implement the rendering logic.
        // Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
        // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
        // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
        public override void Execute(ScriptableRenderContext Context, ref RenderingData renderingData) {
            CommandBuffer CmdBuf = CommandBufferPool.Get();

            Render(CmdBuf, ref renderingData);

            Context.ExecuteCommandBuffer(CmdBuf);
            CmdBuf.Clear();
            CommandBufferPool.Release(CmdBuf);
        }

        // Cleanup any allocated resources that were created during the execution of this render pass.
        public override void OnCameraCleanup(CommandBuffer cmd) {
        }

        public void SetupAttribute(RTHandle InColorRTHandle, RTHandle InDepthRTHandle) { 
            m_CameraColorTarget = InColorRTHandle;
            m_CameraDepthTarget = InDepthRTHandle;
        }

        private void SimpleRender(CommandBuffer CmdBuf) {
            CmdBuf.SetGlobalTexture(Shader.PropertyToID("_BlueNoiseTex"), m_NoiseTexture);
            Blitter.BlitCameraTexture(CmdBuf, m_CameraColorTarget, m_CameraColorTarget, m_Material, 0);
        }

        private void RadianceCascadesRender(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            // Step0. Setup all base Uniform
            CmdBuf.SetGlobalTexture(Shader.PropertyToID("_BlueNoiseTex"), m_NoiseTexture);
            CmdBuf.SetGlobalVectorArray(Shader.PropertyToID("Cascade_ProbeNum_TexSize"), Cascade_ProbeNum_TexSize);
            CmdBuf.SetGlobalVectorArray(Shader.PropertyToID("Cascade_ProbeSize_AngleSize"), Cascade_ProbeSize_AngleSize);
            // Step1. Construct SDF (We use analytic SDF insteadly)
            GenerateSdf(CmdBuf, ref renderingData);
            CmdBuf.SetGlobalTexture(Shader.PropertyToID("_Sdf_Texture"), TempRTHandle_Sdf[2]);
            // Step2. Construct All Level Raymarching Result Texture
            using (new ProfilingScope(CmdBuf, m_RayMarchingProfilingSampler)) {
                for (int CascadeLevel = 0; CascadeLevel < CascadeLevelNum; CascadeLevel++) {
                    CmdBuf.SetGlobalInt(Shader.PropertyToID("Cascade_Level"), CascadeLevel);
                    CmdBuf.SetGlobalFloat(Shader.PropertyToID("Cascade_Marching_Begin"), (CascadeLevel == 0 ? 0 : Mathf.Pow(CascadeN_RayMarchingLengthRate, CascadeLevel - 1)) * Cascade0_RayMarchingLength);
                    CmdBuf.SetGlobalFloat(Shader.PropertyToID("Cascade_Marching_End"), Mathf.Pow(CascadeN_RayMarchingLengthRate, CascadeLevel) * Cascade0_RayMarchingLength);

                    Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_RayMarching[CascadeLevel], TempRTHandle_RayMarching[CascadeLevel], m_RCMaterial, 0);
                }
            }

            // Step3. Merge This Texture To Cascade 0
            // RayMarchingResult       MergeResult          AddResult
            //        n                  n + 1                  n
            var CurrentMergeTexIndex = 0;
            using (new ProfilingScope(CmdBuf, m_MergeProfilingSampler)) {
                Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_RayMarching[CascadeLevelNum - 1], TempRTHandle_Merge[CurrentMergeTexIndex], 0, false);
                for (int CascadeLevel = CascadeLevelNum - 2; CascadeLevel >= 0; CascadeLevel--) {
                    CurrentMergeTexIndex = CurrentMergeTexIndex ^ 1;

                    CmdBuf.SetGlobalInt(Shader.PropertyToID("Cascade_Level"), CascadeLevel);
                    CmdBuf.SetGlobalTexture(Shader.PropertyToID("Cascade_MergeTex"), TempRTHandle_Merge[CurrentMergeTexIndex ^ 1]);

                    Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_RayMarching[CascadeLevel], TempRTHandle_Merge[CurrentMergeTexIndex], m_RCMaterial, 1);
                }
            }
            // Step3.5. Debug Render Image By Merge Result 0
            // using (new ProfilingScope(CmdBuf, m_RenderProfilingSampler)) {
            //    for (int CascadeLevel = 0; CascadeLevel < CascadeLevelNum; CascadeLevel++) {
            //        CmdBuf.SetGlobalInt(Shader.PropertyToID("Cascade_Level"), CascadeLevel);
            //        Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_RayMarching[CascadeLevel], m_CameraColorTarget, m_RCMaterial, 2);
            //    }
            // }

            // Step4. Render Image By Merge Result 0
            using (new ProfilingScope(CmdBuf, m_RenderProfilingSampler)) {
                CmdBuf.SetGlobalInt(Shader.PropertyToID("Cascade_Level"), 0);
                Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Merge[CurrentMergeTexIndex], m_CameraColorTarget, m_RCMaterial, 2);
            }
        }

        private void RadianceCascadesOptRender(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            // Step0. Setup all base Uniform
            CmdBuf.SetGlobalTexture(Shader.PropertyToID("_BlueNoiseTex"), m_NoiseTexture);
            CmdBuf.SetGlobalVectorArray(Shader.PropertyToID("Cascade_ProbeNum_TexSize"), Cascade_ProbeNum_TexSize);
            CmdBuf.SetGlobalVectorArray(Shader.PropertyToID("Cascade_ProbeSize_AngleSize"), Cascade_ProbeSize_AngleSize);
            // Step1. Construct SDF (We use analytic SDF insteadly)
            GenerateSdf(CmdBuf, ref renderingData);
            CmdBuf.SetGlobalTexture(Shader.PropertyToID("_Sdf_Texture"), TempRTHandle_Sdf[2]);
            // Step2. Construct All Level Raymarching Result Texture
            var CurrentMergeTexIndex = 0;
            using (new ProfilingScope(CmdBuf, m_CombineProfilingSampler)) {
                for (int CascadeLevel = CascadeLevelNum - 1; CascadeLevel >= 0; CascadeLevel--) {
                    CurrentMergeTexIndex = CurrentMergeTexIndex ^ 1;
                    CmdBuf.SetGlobalInt(Shader.PropertyToID("Cascade_Level"), CascadeLevel);
                    CmdBuf.SetGlobalFloat(Shader.PropertyToID("Cascade_Marching_Begin"), (CascadeLevel == 0 ? 0 : Mathf.Pow(CascadeN_RayMarchingLengthRate, CascadeLevel - 1)) * Cascade0_RayMarchingLength);
                    CmdBuf.SetGlobalFloat(Shader.PropertyToID("Cascade_Marching_End"), Mathf.Pow(CascadeN_RayMarchingLengthRate, CascadeLevel) * Cascade0_RayMarchingLength);

                    if (CascadeLevel == CascadeLevelNum - 1) {
                        Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Merge[CurrentMergeTexIndex ^ 1], TempRTHandle_Merge[CurrentMergeTexIndex], m_RCMaterial, 0);
                    } else {
                        Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Merge[CurrentMergeTexIndex ^ 1], TempRTHandle_Merge[CurrentMergeTexIndex], m_RCMaterial, 3);
                    }
                }
            }
            
            // Step3. Render Image By Merge Result 0
            using (new ProfilingScope(CmdBuf, m_RenderProfilingSampler)) {
                CmdBuf.SetGlobalInt(Shader.PropertyToID("Cascade_Level"), 0);
                Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Merge[CurrentMergeTexIndex], m_CameraColorTarget, m_RCMaterial, 2);
            }
        }

        private void Render(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            switch (UsedPipeline) {
                case Pipeline.Simple: { SimpleRender(CmdBuf); break; }
                case Pipeline.RadianceCascades: { RadianceCascadesRender(CmdBuf, ref renderingData); break; }
                case Pipeline.RadianceCascadesOpt: { RadianceCascadesOptRender(CmdBuf, ref renderingData); break; }
            }
        }

        private void GenerateSdf(CommandBuffer CmdBuf, ref RenderingData renderingData) {
            int CurrentJFATexIndex = 0;
            using (new ProfilingScope(CmdBuf, m_JumpFloodInitProfilingSampler)) {
                Blitter.BlitCameraTexture(CmdBuf, m_CameraColorTarget, TempRTHandle_Sdf[CurrentJFATexIndex], m_JFMaterial, 0);
            }

            int MaxStep = Math.Max(renderingData.cameraData.cameraTargetDescriptor.width, renderingData.cameraData.cameraTargetDescriptor.height);

            CmdBuf.SetGlobalTexture(Shader.PropertyToID("_ColorTexture"), m_CameraColorTarget);
            using (new ProfilingScope(CmdBuf, m_JumpFloodLoopProfilingSampler)) {
                for (float JumpStepIndex = Mathf.Ceil(Mathf.Log(MaxStep) / Mathf.Log(2)); JumpStepIndex >= 0; JumpStepIndex--) {
                    CurrentJFATexIndex ^= 1;

                    float JumpStep = Mathf.Pow(2, JumpStepIndex);
                    CmdBuf.SetGlobalFloat(Shader.PropertyToID("JumpLength"), JumpStep);
                    Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Sdf[CurrentJFATexIndex ^ 1], TempRTHandle_Sdf[CurrentJFATexIndex], m_JFMaterial, 1);

                    // Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Sdf[CurrentJFATexIndex], TempRTHandle_Sdf[2], m_JFMaterial, 2);
                }
            }

            using (new ProfilingScope(CmdBuf, m_JumpFloodInitProfilingSampler)) {
                CmdBuf.SetGlobalTexture(Shader.PropertyToID("_ColorTexture"), m_CameraColorTarget);
                Blitter.BlitCameraTexture(CmdBuf, TempRTHandle_Sdf[CurrentJFATexIndex], TempRTHandle_Sdf[2], m_JFMaterial, 2);
            }
        }
    }

    RCPostRenderPass m_ScriptablePass;

    // public void Update()
    // {
    //     m_ScriptablePass.Cascade0_RayMarchingLength              = Cascade0_RayMarchingLength;
    //     m_ScriptablePass.CascadeN_RayMarchingLengthRate          = CascadeN_RayMarchingLengthRate;
    //     m_ScriptablePass.Cascade0_ProbeSizePix                   = Cascade0_ProbeSizePix;
    //     m_ScriptablePass.Cascade0_AngleSize                      = Cascade0_AngleSize;
    //     m_ScriptablePass.CascadeN_AngleSizeRate                  = CascadeN_AngleSizeRate;
    // }

    /// <inheritdoc/>
    public override void Create()
    {
        m_Material = CoreUtils.CreateEngineMaterial(m_Shader);
        m_RCMaterial = CoreUtils.CreateEngineMaterial(m_RCShader);
        m_JFMaterial = CoreUtils.CreateEngineMaterial(m_JFShader);

        m_ScriptablePass = new RCPostRenderPass();
        // Configures where the render pass should be injected.
        m_ScriptablePass.m_Material = m_Material;
        m_ScriptablePass.m_RCMaterial = m_RCMaterial;
        m_ScriptablePass.m_JFMaterial = m_JFMaterial;
        m_ScriptablePass.m_NoiseTexture = m_NoiseTexture;
        m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
    }

    protected override void Dispose(bool disposing)
    {
        CoreUtils.Destroy(m_Material);
        CoreUtils.Destroy(m_RCMaterial);
    }

    // Here you can inject one or multiple render passes in the renderer.
    // This method is called when setting up the renderer once per-camera.
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (renderingData.cameraData.cameraType == CameraType.Game)
            renderer.EnqueuePass(m_ScriptablePass);
    }

    public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
    {
        if (renderingData.cameraData.cameraType == CameraType.Game)
        {
            // Calling ConfigureInput with the ScriptableRenderPassInput.Color argument
            // ensures that the opaque texture is available to the Render Pass.
            m_ScriptablePass.ConfigureInput(ScriptableRenderPassInput.Color);
            m_ScriptablePass.SetupAttribute(renderer.cameraColorTargetHandle, renderer.cameraDepthTargetHandle);
        }
    }
}